package connect5.ia;

import java.util.ArrayList;
import java.util.List;

import connect5.Grille;

/**
 * 
 * @author Jean-Sébastien Carrier 09111720
 * @author Guillaume Paquette Boisclair 09129089
 * 
 */

public class GridAnalyser {

	private static final int MIN_LINE_LENGTH = 5;
	private static final int MIN_COL_LENGTH = 5;

	public long analyseGrid(Grille grid) {

		long cumulMatrixConfigValue = 0;
		long horizontal = 0;
		long vertical = 0;
		long diagonal1 = 0;
		long diagonal2 = 0;

		horizontal = analyseHorizontally(grid);
		vertical = analyseVertically(grid);
		diagonal1 = analyseDiagonaly1(grid);
		diagonal2 = analyseDiagonaly2(grid);

		if (horizontal == 2000000000 || vertical == 2000000000
				|| diagonal1 == 2000000000 || diagonal2 == 2000000000) {
			return 2000000000;
		}
		if (horizontal == -2000000000 || vertical == -2000000000
				|| diagonal1 == -2000000000 || diagonal2 == -2000000000) {
			return -2000000000;
		}

		cumulMatrixConfigValue = horizontal + vertical + diagonal1 + diagonal2;
		return cumulMatrixConfigValue;
	}

	public long analyseHorizontally(Grille grid) {
		Grille temp = grid.clone();

		long matrixConfigValue = 0;

		for (byte[] actualLine : temp.getData()) {

			String lineString = convertByteArrayToString(actualLine);

			int value = evaluateLineConfig(lineString);
			if (value == -2000000000 || value == 2000000000) {
				return value;
			}

			else {
				matrixConfigValue += value;
			}
		}

		return matrixConfigValue;
	}

	public long analyseVertically(Grille grid) {

		int nbLine = extractNumberOfLine(grid);
		int nbCol = extractNumberOfColumn(grid);

		Grille invertedGrid = invertGrid(grid, nbLine, nbCol);

		return analyseHorizontally(invertedGrid);
	}

	public long analyseDiagonaly1(Grille grid) {

		int nbLine = extractNumberOfLine(grid);
		int nbCol = extractNumberOfColumn(grid);

		long diagoConfigValue = 0;

		if (nbLine >= MIN_LINE_LENGTH && nbCol >= MIN_COL_LENGTH) {

			int ii = 0;
			int jj = 0;

			while (ii < nbCol - 4) {

				int i = ii;
				int j = 0;
				StringBuilder line = new StringBuilder();

				// prochaine ligne du container
				while (i < nbCol && j < nbLine) {
					// mettre la (i,j) valeurs dans un container
					line.append(grid.get(i, j));
					i++;
					j++;
				}
				ii++;
				diagoConfigValue += evaluateLineConfig(line.toString());
			}

			ii = 0;
			jj = 1;

			while (jj < nbLine - 4) {

				int j = jj;
				int i = 0;
				StringBuilder line = new StringBuilder();
				// prochaine ligne du container
				while (i < nbCol && j < nbLine) {
					// mettre la (i,j) valeurs dans un container
					line.append(grid.get(i, j));
					i++;
					j++;
				}
				jj++;
				diagoConfigValue += evaluateLineConfig(line.toString());
			}

		}

		return diagoConfigValue;
	}

	public long analyseDiagonaly2(Grille grid) {

		int nbLine = extractNumberOfLine(grid);
		int nbCol = extractNumberOfColumn(grid);

		long diagoConfigValue = 0;

		if (nbLine >= MIN_LINE_LENGTH && nbCol >= MIN_COL_LENGTH) {

			int ii = nbCol - 1;
			int jj = nbLine - 1;

			while (ii > 3) {

				int i = ii;
				int j = 0;
				StringBuilder line = new StringBuilder();

				// prochaine ligne du container
				while (i >= 0 && j < nbLine) {
					// mettre la (i,j) valeurs dans un container
					line.append(grid.get(i, j));
					i--;
					j++;
				}
				ii--;
				diagoConfigValue += evaluateLineConfig(line.toString());
			}

			ii = nbCol - 1;
			jj = 1;

			while (jj < 3) {

				int j = jj;
				int i = nbCol - 1;
				StringBuilder line = new StringBuilder();
				// prochaine ligne du container
				while (i >= 0 && j < nbLine) {
					// mettre la (i,j) valeurs dans un container
					line.append(grid.get(i, j));
					i--;
					j++;
				}
				jj++;
				diagoConfigValue += evaluateLineConfig(line.toString());
			}

		}

		return diagoConfigValue;
	}

	private int evaluateLineConfig(String lineString) {
		List<Pattern> patternFound = new ArrayList<Pattern>();

		int cumulativeValue = 0;

		for (Pattern p : Pattern.values()) {
			if (lineString.contains(p.BBBBB.getInnerStr())) {
				return -2000000000;
			} else if (lineString.contains(p.NNNNN.getInnerStr())) {
				return 2000000000;
			}

			if (lineString.contains(p.getInnerStr())) {
				patternFound.add(p);
				cumulativeValue += p.getWeigth();
			}
		}

		return cumulativeValue;
	}

	private int extractNumberOfColumn(Grille srcGrid) {
		return srcGrid.getData()[0].length;
	}

	private int extractNumberOfLine(Grille srcGrid) {
		return srcGrid.getData().length;
	}

	private String convertByteArrayToString(byte[] actualLine) {
		StringBuilder line = new StringBuilder();

		for (byte oneByte : actualLine) {
			if (oneByte == 1)
				line.append('1');
			else if (oneByte == 2)
				line.append('2');
			else
				line.append('0');
		}
		return line.toString();
	}

	private Grille invertGrid(Grille srcGrid, int nbLine, int nbCol) {
		Grille invertedGrid = new Grille(nbLine, nbCol);
		invertedGrid.reset();

		for (int i = 0; i < nbLine; ++i) {
			for (int j = 0; j < nbCol; ++j) {
				invertedGrid.set(j, i, srcGrid.get(i, j));
			}
		}

		return invertedGrid;
	}
}
